﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;

namespace NetFrameworkExtensions.Configuration
{
  public abstract class ConfigurationElementCollectionBase<TBaseType> 
    : ConfigurationElementCollection
    where TBaseType: ConfigurationElement
  {
    private static readonly object staticLock = new object();
    private static Dictionary<string, Type> folderElementTypes;
    private static Type GetElementType(string elementName)
    {
      EnsureLoad();
      Type type;
      if (folderElementTypes.TryGetValue(elementName, out type))
        return type;
      return null;
    }
    private static void EnsureLoad()
    {
      if (folderElementTypes == null)
      {
        lock (staticLock)
        {
          var temp = new Dictionary<string, Type>();
          foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.GetExportedTypes()).Where(t => !t.IsAbstract && typeof(TBaseType).IsAssignableFrom(t)))
          {
            var attr = type.GetCustomAttributes(typeof(ConfigNameAttribute), false)
              .OfType<ConfigNameAttribute>().SingleOrDefault();
            if (attr != null && !String.IsNullOrEmpty(attr.Name))
            {
              if (temp.ContainsKey(attr.Name))
                throw new FormatException("There are more than two FolderElements with the same display name");
              temp.Add(attr.Name, type);
            }
          }
          folderElementTypes = temp;
        }
      }
    }

    protected override ConfigurationElement CreateNewElement(string elementName)
    {
      var type = GetElementType(elementName);
      if (type == null)
        throw new FormatException("Invalid element name for config collection: " + elementName);
      return (ConfigurationElement) Activator.CreateInstance(type);
    }

  }
}
